home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / mail / xmailbox.4-s / xmailbox / xmailbox-2.4 / Mailbox.c < prev    next >
C/C++ Source or Header  |  1996-06-30  |  29KB  |  1,063 lines

  1. /*
  2.  * Copyright (c) 1994-96  Dimitrios P. Bouras and William K. W. Cheung
  3.  * 
  4.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  5.  * of this software and associated documentation files (the "Software"), to deal
  6.  * in the Software without restriction, including without limitation the rights
  7.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8.  * copies of the Software, and to permit persons to whom the Software is
  9.  * furnished to do so, subject to the following conditions:
  10.  * 
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  17.  * X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  18.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20.  * 
  21.  * Except as contained in this notice, the name of the X Consortium shall not be
  22.  * used in advertising or otherwise to promote the sale, use or other dealings
  23.  * in this Software without prior written authorization from the X Consortium.
  24.  * 
  25.  * Derived from the MIT X11R5 xbiff, written by Jim Fulton, which is
  26.  * copyrighted (c) 1988 X Consortium.
  27.  *
  28.  * Mailbox XPM additions-modifications:  Dimitrios P. Bouras
  29.  * Audio support and XPM icon animation: William K. W. Cheung
  30.  */
  31.  
  32. #include <X11/IntrinsicP.h>        /* for toolkit stuff */
  33. #include <X11/StringDefs.h>        /* for useful atom names */
  34. #include <X11/cursorfont.h>        /* for cursor constants */
  35. #include <X11/Xosdefs.h>        /* for X_NOT_POSIX def */
  36. #include <sys/stat.h>            /* for stat() ** needs types.h ***/
  37. #include <sys/signal.h>            /* for signal() */
  38. #include <stdio.h>                /* for printing error messages */
  39. #include <pwd.h>                /* for getting username */
  40. #include <stdlib.h>                /* for getenv() */
  41. #include <string.h>
  42.  
  43. #ifndef NO_AUDIO
  44. #ifdef NCD_AUDIO
  45. #include <audio/audiolib.h>
  46. #include <audio/soundlib.h>
  47.  
  48. static AuServer *aud;            /* Audio server handler */
  49. #elif defined(RPLAY_AUDIO)
  50. #include <rplay.h>
  51. #endif /* ifdef NCD_AUDIO */
  52. #endif /* ifndef NO_AUDIO */
  53.  
  54. #include <sys/file.h>
  55. #include <sys/fcntl.h>
  56. #include <sys/ioctl.h>
  57.  
  58. #ifndef NO_AUDIO
  59. #ifdef SUN_AUDIO
  60.  
  61. /* Adapted from <multimedia/audio_filehdr.h> */
  62.  
  63. typedef unsigned     u_32;    /* we assume sizeof(unsigned) = 4 */
  64.  
  65. typedef struct {
  66.     u_32        magic;        /* magic number */
  67.     u_32        hdr_size;    /* size of this header */
  68.     u_32        data_size;    /* length of data (optional) */
  69.     u_32        encoding;    /* data encoding format */
  70.     u_32        sample_rate;    /* samples per second */
  71.     u_32        channels;    /* number of interleaved channels */
  72. } Audio_filehdr;
  73.  
  74. #if defined(linux) || defined(__FreeBSD__)
  75. #ifdef linux
  76. #include <linux/soundcard.h>
  77. #else
  78. #include <machine/soundcard.h>
  79. #endif /* ifdef linux */
  80.  
  81. #define DEV_MIXER        "/dev/mixer"
  82. #define MAX_VOLUME        100
  83. #define MIN_VOLUME        1
  84. #define RIGHT            0x01
  85. #define LEFT            0x02
  86.  
  87. typedef struct stereovolume
  88. {
  89.     unsigned char left;
  90.     unsigned char right;
  91.     unsigned char pad[2];
  92. } StereoVolume;
  93.  
  94. void setvolume(int which, unsigned char setting, StereoVolume *volptr)
  95. {
  96.     if ( setting < MIN_VOLUME )
  97.         setting=MIN_VOLUME;
  98.     if ( setting > MAX_VOLUME )
  99.         setting=MAX_VOLUME;
  100.  
  101.     if ( which&RIGHT )
  102.         volptr->right=setting;
  103.     if ( which&LEFT )
  104.         volptr->left=setting;
  105. }
  106. #else
  107. #include <sun/audioio.h>
  108. #endif /* if defined(linux) */
  109. #endif /* ifdef SUN_AUDIO */
  110. #endif /* ifndef NO_AUDIO */
  111.  
  112. #ifndef X_NOT_POSIX
  113. #ifdef _POSIX_SOURCE
  114. # include <sys/wait.h>
  115. #else
  116. #define _POSIX_SOURCE
  117. # include <sys/wait.h>
  118. #undef _POSIX_SOURCE
  119. #endif
  120. # define waitCode(w)    WEXITSTATUS(w)
  121. # define waitSig(w)    WIFSIGNALED(w)
  122. typedef int        waitType;
  123. # define INTWAITTYPE
  124. #else /* ! X_NOT_POSIX */
  125. #ifdef SYSV
  126. # define waitCode(w)    (((w) >> 8) & 0x7f)
  127. # define waitSig(w)    ((w) & 0xff)
  128. typedef int        waitType;
  129. # define INTWAITTYPE
  130. #else
  131. # include    <sys/wait.h>
  132. # define waitCode(w)    ((w).w_T.w_Retcode)
  133. # define waitSig(w)    ((w).w_T.w_Termsig)
  134. typedef union wait    waitType;
  135. #endif /* SYSV else */
  136. #endif /* ! X_NOT_POSIX else */
  137.  
  138. #include "xmail.xpm"        /* for flag up (mail present) bits */
  139. #include "xnomail.xpm"        /* for flag down (mail not here) */
  140.  
  141. #ifndef min
  142. #define min(x,y)    ((x) < (y)? (x): (y))
  143. #endif
  144.  
  145. #include <X11/Xaw/XawInit.h>
  146. #include "MailboxP.h"            /* for implementation mailbox stuff */
  147. #include <X11/Xmu/Drawing.h>
  148. #include <X11/extensions/shape.h>
  149.  
  150. /*
  151.  * The default user interface is to have the mailbox turn itself off whenever
  152.  * the user presses a button in it.  Expert users might want to make this 
  153.  * happen on EnterWindow.  It might be nice to provide support for some sort of
  154.  * exit callback so that you can do things like press q to quit.
  155.  */
  156.  
  157. static char defaultTranslations[] = 
  158.   "<ButtonPress>:  unset()";
  159.  
  160. static void Check(), Set(), Unset();
  161.  
  162. static XtActionsRec actionsList[] = { 
  163.     { "check",    Check },
  164.     { "unset",    Unset },
  165.     { "set",    Set },
  166. };
  167.  
  168. /*
  169.  * Storage for the XPM images for the two mailbox states.
  170.  */
  171. static XpmImage mail_xpmimg[MAX_ANIM_IMAGE];
  172. static XpmImage nomail_xpmimg;
  173.  
  174. /* Initialization of defaults */
  175.  
  176. #define offset(field) XtOffsetOf(Mailbox_XPM_Rec, mailbox.field)
  177. #define goffset(field) XtOffsetOf(WidgetRec, core.field)
  178.  
  179. static XtResource resources[] = {
  180.     { XtNupdate, XtCInterval, XtRInt, sizeof (int),
  181.     offset (update), XtRImmediate, (XtPointer)30 },
  182.     { XtNfile, XtCFile, XtRString, sizeof (String),
  183.     offset (filename), XtRString, NULL },
  184.     { XtNcheckCommand, XtCCheckCommand, XtRString, sizeof(char*),
  185.     offset (check_command), XtRString, NULL },
  186.     { XtNvolume, XtCVolume, XtRInt, sizeof(int),
  187.     offset (volume), XtRImmediate, (XtPointer)33 },
  188.     { XtNonceOnly, XtCBoolean, XtRBoolean, sizeof(Boolean),
  189.     offset (once_only), XtRImmediate, (XtPointer)False },
  190.     { Nmailtool, CMailTool, XtRString, sizeof (String),
  191.     offset (mail_tool), XtRString, NULL },
  192.     { XtNmailAnimUpdate, XtCMailAnimUpdate, XtRInt, sizeof (int),
  193.     offset (mail_animupdate), XtRImmediate, (XtPointer)1000 },
  194.     { XtNmailAnimOnce, XtCMailAnimOnce, XtRBoolean, sizeof (Boolean),
  195.     offset (mail_animonce), XtRImmediate, (XtPointer)False },
  196.     { XtNmailNumOfXpmFile, XtCMailNumOfXpmFile, XtRInt, sizeof (int),
  197.     offset (mail_numofxpmfile), XtRImmediate, (XtPointer)1 },
  198.     { NmailXpmFile, CMailXpmFile, XtRString, sizeof (String),
  199.     offset (mail_xpmfile), XtRString, NULL },
  200.     { NnomailXpmFile, CNomailXpmFile, XtRString, sizeof (String),
  201.     offset (nomail_xpmfile), XtRString, NULL },
  202.     { NmailSndFile, CMailSndFile, XtRString, sizeof (String),
  203.     offset (mail_sndfile), XtRString, NULL },
  204.     { NmailSndComm, CMailSndComm, XtRString, sizeof (String),
  205.     offset (mail_sndcomm), XtRString, NULL },
  206. };
  207.  
  208. #undef offset
  209.  
  210. static void GetMailFile(), CloseDown(), ReadIconFile(), DefaultXpmImage();
  211. static void check_mailbox(), redraw_mailbox(), beep();
  212. static void Initialize(), Realize(), Destroy(), Redisplay();
  213. static Boolean SetValues();
  214.  
  215. Mailbox_XPM_ClassRec mailboxClassRec = {
  216.     { /* core fields */
  217.     /* superclass                */    (WidgetClass) &simpleClassRec,
  218.     /* class_name                */    "Mailbox",
  219.     /* widget_size                */    sizeof(Mailbox_XPM_Rec),
  220.     /* class_initialize            */    XawInitializeWidgetSet,
  221.     /* class_part_initialize    */    NULL,
  222.     /* class_inited                */    FALSE,
  223.     /* initialize                */    Initialize,
  224.     /* initialize_hook            */    NULL,
  225.     /* realize                    */    Realize,
  226.     /* actions                    */    actionsList,
  227.     /* num_actions                */    XtNumber(actionsList),
  228.     /* resources                */    resources,
  229.     /* resource_count            */    XtNumber(resources),
  230.     /* xrm_class                */    NULLQUARK,
  231.     /* compress_motion            */    TRUE,
  232.     /* compress_exposure        */    TRUE,
  233.     /* compress_enterleave        */    TRUE,
  234.     /* visible_interest            */    FALSE,
  235.     /* destroy                    */    Destroy,
  236.     /* resize                    */    NULL,
  237.     /* expose                    */    Redisplay,
  238.     /* set_values                */    SetValues,
  239.     /* set_values_hook            */    NULL,
  240.     /* set_values_almost        */    XtInheritSetValuesAlmost,
  241.     /* get_values_hook            */    NULL,
  242.     /* accept_focus                */    NULL,
  243.     /* version                    */    XtVersion,
  244.     /* callback_private            */    NULL,
  245.     /* tm_table                    */    defaultTranslations,
  246.     /* query_geometry            */    XtInheritQueryGeometry,
  247.     /* display_accelerator        */    XtInheritDisplayAccelerator,
  248.     /* extension                */    NULL
  249.     },
  250.     { /* simple fields */
  251.     /* change_sensitive         */    XtInheritChangeSensitive
  252.     },
  253.     { /* mailbox fields */
  254.     /* ignore                   */    0
  255.     }
  256. };
  257.  
  258. WidgetClass mailboxWidgetClass = (WidgetClass) &mailboxClassRec;
  259.  
  260.  
  261. /*
  262.  * widget initialization
  263.  */
  264.  
  265. static GC get_mailbox_gc (w)
  266.     MailboxWidget w;
  267. {
  268.     XtGCMask valuemask;
  269.     XGCValues xgcv;
  270.  
  271.     valuemask = GCFunction | GCGraphicsExposures;
  272.     xgcv.function = GXcopy;
  273.     xgcv.graphics_exposures = False;    /* this is Bool, not Boolean */
  274.     return (XtGetGC ((Widget) w, valuemask, &xgcv));
  275. }
  276.  
  277. int zombiekiller()
  278. {
  279.     int    status;
  280.  
  281.     while (wait3(&status, WNOHANG, 0) >= 0);
  282. #ifdef linux
  283.     signal(SIGCHLD, (SignalHandler)zombiekiller);
  284. #endif
  285. }
  286.  
  287. /* ARGSUSED */
  288. static void Initialize (request, new)
  289.     Widget request, new;
  290. {
  291.     MailboxWidget w = (MailboxWidget) new;
  292.     int shape_event_base, shape_error_base;
  293.  
  294. #ifdef SYSV
  295.     signal(SIGCLD, zombiekiller);
  296. #elif defined(linux)
  297.     signal(SIGCHLD, (SignalHandler)zombiekiller);
  298. #else
  299.     signal(SIGCHLD, zombiekiller);
  300. #endif
  301.  
  302.     if ( !XShapeQueryExtension (XtDisplay (w), &shape_event_base,
  303.                                                &shape_error_base)) {
  304.     fprintf (stderr, "%s:  shape extensions not supported!\n",
  305.          "Mailbox widget");
  306.     CloseDown (w, 1);
  307.     }
  308.  
  309.     w->mailbox.shape_cache.mask = None;
  310.     w->mailbox.gc = get_mailbox_gc (w);
  311.     w->mailbox.interval_id = (XtIntervalId) 0;
  312.     w->mailbox.anim_int_id = (XtIntervalId) -1;
  313.     w->mailbox.first_trig = 1;
  314.     w->mailbox.flag_up = FALSE;
  315.     w->mailbox.last_size = 0;
  316.     w->mailbox.anim_id = 0;
  317.  
  318.     if ((w->mailbox.mail_numofxpmfile < 1) 
  319.         || (w->mailbox.mail_numofxpmfile > MAX_ANIM_IMAGE)) {
  320.         fprintf (stderr,
  321.                  "%s:  Number of Xpm Images must be between 1 and 8 !\n",
  322.                  "Mailbox widget");
  323.         CloseDown (w, 1);
  324.     }
  325.  
  326.     if (!w->mailbox.filename) GetMailFile (w);
  327.  
  328.     /*
  329.      * read the XPM files from the resources, if any, and create
  330.      * XpmImages, or create XpmImages from default image data
  331.      */
  332.  
  333.     w->mailbox.full[0].xpmimg = None;
  334.     if (w->mailbox.mail_xpmfile) ReadIconFile(w, True);
  335.     if (w->mailbox.full[0].xpmimg == None) DefaultXpmImage(w, True);
  336.  
  337.     w->mailbox.empty.xpmimg = None;
  338.     if (w->mailbox.nomail_xpmfile) ReadIconFile(w, False);
  339.     if (w->mailbox.empty.xpmimg == None) DefaultXpmImage(w, False);
  340.  
  341. #define _MAX(x,y) ((x>y)?x:y)
  342.     w->core.width = _MAX( w->mailbox.full[0].width, w->mailbox.empty.width);
  343.     w->core.height = _MAX( w->mailbox.full[0].height, w->mailbox.empty.height);
  344. #undef _MAX
  345.  
  346.     return;
  347. }
  348.  
  349.  
  350. /*
  351.  * action procedures
  352.  */
  353.  
  354. /*
  355.  * pretend there is new mail; put widget in flagup state
  356.  */
  357.  
  358. /* ARGSUSED */
  359. static void Set (gw, event, params, nparams)
  360.     Widget gw;
  361.     XEvent *event;
  362.     String *params;
  363.     Cardinal *nparams;
  364. {
  365.     MailboxWidget w = (MailboxWidget) gw;
  366.  
  367.     w->mailbox.last_size = -1;
  368.  
  369.     check_mailbox (w, TRUE, FALSE);    /* redraw, no reset */
  370.  
  371.     return;
  372. }
  373.  
  374.  
  375. /*
  376.  * ack the existing mail; put widget in flagdown state
  377.  */
  378.  
  379. /* ARGSUSED */
  380. static void Unset (gw, event, params, nparams)
  381.     Widget gw;
  382.     XEvent *event;
  383.     String *params;
  384.     Cardinal *nparams;
  385. {
  386.     MailboxWidget w = (MailboxWidget) gw;
  387.  
  388.     check_mailbox (w, TRUE, TRUE);    /* redraw, reset */
  389.  
  390.     return;
  391. }
  392.  
  393.  
  394. /*
  395.  * look to see if there is new mail; if so, Set, else Unset
  396.  */
  397.  
  398. /* ARGSUSED */
  399. static void Check (gw, event, params, nparams)
  400.     Widget gw;
  401.     XEvent *event;
  402.     String *params;
  403.     Cardinal *nparams;
  404. {
  405.     MailboxWidget w = (MailboxWidget) gw;
  406.  
  407.     check_mailbox (w, TRUE, FALSE);    /* redraw, no reset */
  408.  
  409.     return;
  410. }
  411.  
  412.  
  413. /* ARGSUSED */
  414. static void clock_tic_anim (client_data, id)
  415.     XtPointer client_data;
  416.     XtIntervalId *id;
  417. {
  418.     MailboxWidget w = (MailboxWidget) client_data;
  419.  
  420.     redraw_mailbox(w);
  421.     /*
  422.      * and reset the timer
  423.      */
  424.  
  425.     w->mailbox.anim_int_id =
  426.         XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  427.                  w->mailbox.mail_animupdate, clock_tic_anim, client_data);
  428.  
  429.     return;
  430. }
  431.  
  432. /* ARGSUSED */
  433. static void clock_tic (client_data, id)
  434.     XtPointer client_data;
  435.     XtIntervalId *id;
  436. {
  437.     MailboxWidget w = (MailboxWidget) client_data;
  438.  
  439.     check_mailbox (w, FALSE, FALSE);    /* no redraw, no reset */
  440.  
  441.     /*
  442.      * and reset the timer
  443.      */
  444.  
  445.     w->mailbox.interval_id =
  446.     XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  447.              w->mailbox.update * 1000, clock_tic, client_data);
  448.  
  449.     return;
  450. }
  451.  
  452. static void Realize (gw, valuemaskp, attr)
  453.     Widget                    gw;
  454.     XtValueMask                *valuemaskp;
  455.     XSetWindowAttributes    *attr;
  456. {
  457.     MailboxWidget        w = (MailboxWidget) gw;
  458.     register Display    *dpy = XtDisplay (w);
  459.     XpmAttributes        xpm_attr;
  460.     int                    i;
  461.  
  462.     *valuemaskp |= (CWBitGravity | CWCursor);
  463.     attr->bit_gravity = ForgetGravity;
  464.     attr->cursor = XCreateFontCursor (dpy, XC_top_left_arrow);
  465.  
  466.     (*mailboxWidgetClass->core_class.superclass->core_class.realize)
  467.     (gw, valuemaskp, attr);
  468.  
  469.     /*
  470.      * build the pixmaps for the two mailbox
  471.      * states from the saved XpmImages
  472.      */
  473.     xpm_attr.valuemask = 0;
  474.  
  475.     for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {    
  476.         XpmCreatePixmapFromXpmImage (dpy, w->core.window,
  477.                                      w->mailbox.full[i].xpmimg,
  478.                                      &w->mailbox.full[i].pixmap,
  479.                                      &w->mailbox.full[i].bitmap, &xpm_attr);
  480.     }
  481.  
  482.     xpm_attr.valuemask = 0;
  483.     XpmCreatePixmapFromXpmImage (dpy, w->core.window, w->mailbox.empty.xpmimg,
  484.                                  &w->mailbox.empty.pixmap,
  485.                                  &w->mailbox.empty.bitmap, &xpm_attr);
  486.  
  487.     w->mailbox.interval_id = 
  488.     XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  489.                      w->mailbox.update * 1000, clock_tic, (XtPointer) w);
  490.  
  491.     w->mailbox.shape_cache.mask = None;
  492.  
  493.     check_mailbox (w, TRUE, FALSE);
  494.  
  495.     return;
  496. }
  497.  
  498.  
  499. static void Destroy (gw)
  500.     Widget gw;
  501. {
  502.     MailboxWidget w = (MailboxWidget) gw;
  503.     Display *dpy = XtDisplay (gw);
  504.     int    i;
  505.  
  506.     XtFree (w->mailbox.filename);
  507.     if (w->mailbox.interval_id) XtRemoveTimeOut (w->mailbox.interval_id);
  508.     if (w->mailbox.anim_int_id != -1) XtRemoveTimeOut (w->mailbox.anim_int_id);
  509.     XtReleaseGC(gw, w->mailbox.gc);
  510. #define freepix(p) if (p) XFreePixmap (dpy, p)
  511.     for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {
  512.         freepix (w->mailbox.full[i].bitmap);    /* until cvter does ref cnt */
  513.         freepix (w->mailbox.full[i].pixmap);
  514.     }
  515.     freepix (w->mailbox.empty.bitmap);            /* until cvter does ref cnt */
  516.     freepix (w->mailbox.empty.pixmap);
  517.     freepix (w->mailbox.shape_cache.mask);
  518. #undef freepix
  519.     return;
  520. }
  521.  
  522.  
  523. static void Redisplay (gw)
  524.     Widget gw;
  525. {
  526.     MailboxWidget w = (MailboxWidget) gw;
  527.  
  528.     check_mailbox (w, TRUE, FALSE);
  529. }
  530.  
  531.  
  532. static void check_mailbox (w, force_redraw, reset)
  533.     MailboxWidget w;
  534.     Boolean force_redraw, reset;
  535. {
  536.     long mailboxsize = 0;
  537.     Boolean readSinceLastWrite = FALSE;
  538.     int pid;
  539.  
  540.     if (w->mailbox.check_command != NULL) {
  541.         waitType wait_status;
  542.         int    check_status;
  543. #ifdef INTWAITTYPE
  544.         wait_status = system(w->mailbox.check_command);
  545. #else
  546.         wait_status.w_status = system(w->mailbox.check_command);
  547. #endif
  548.         check_status = waitCode(wait_status);
  549.  
  550.         /* error in sh checkCommand execution */
  551.         if (waitSig(wait_status))
  552.             check_status = 2;        /* act as if there is no mail */
  553.  
  554.         switch (check_status) {
  555.           case 0:
  556.             mailboxsize = w->mailbox.last_size + 1;
  557.             break;
  558.           case 2:
  559.             mailboxsize = 0;
  560.             break;
  561.           default:        /* treat everything else as no change */
  562.                         /* case 1 is no change */
  563.             mailboxsize = w->mailbox.last_size;
  564.         }
  565.     } else {
  566.         struct stat st;
  567.         if (stat (w->mailbox.filename, &st) == 0) {
  568.             mailboxsize = st.st_size;
  569.             readSinceLastWrite = (st.st_atime > st.st_mtime);
  570.         }
  571.     }
  572.  
  573.     /*
  574.      * Now check for changes.  If reset is set then we want to pretent that
  575.      * there is no mail.  If the mailbox is empty then we want to turn off
  576.      * the flag.  Otherwise if the mailbox has changed size then we want to
  577.      * put the flag up, unless the mailbox has been read since the last 
  578.      * write.
  579.      *
  580.      * The cases are:
  581.      *    o  forced reset by user                        DOWN
  582.      *    o  no mailbox or empty (zero-sized) mailbox    DOWN
  583.      *    o  if read after most recent write              DOWN
  584.      *    o  same size as last time                      no change
  585.      *    o  bigger than last time                       UP
  586.      *    o  smaller than last time but non-zero         UP
  587.      *
  588.      * The last two cases can be expressed as different from last
  589.      * time and non-zero.
  590.      */
  591.  
  592.     if (reset) {                        /* forced reset */
  593.         w->mailbox.flag_up = FALSE;
  594.         force_redraw = TRUE;
  595.         if (w->mailbox.mail_tool) {
  596.             pid = fork();
  597.             if (pid == 0) {                /* Child process */
  598.                 system(w->mailbox.mail_tool);
  599.                 _exit(0);
  600.             }
  601.         }
  602.     } else if (mailboxsize == 0) {        /* no mailbox or empty */
  603.         w->mailbox.flag_up = FALSE;
  604.         if (w->mailbox.last_size > 0)
  605.             force_redraw = TRUE;        /* if change */
  606.     } else if (readSinceLastWrite) {     /* only when checkCommand is NULL */
  607.     /* mailbox has been read after most recent write */
  608.         if (w->mailbox.flag_up) {
  609.             w->mailbox.flag_up = FALSE;
  610.             force_redraw = TRUE;
  611.         }
  612.     } else if (mailboxsize != w->mailbox.last_size) {  /* different size */
  613.         if (!w->mailbox.once_only || !w->mailbox.flag_up)
  614.             beep(w); 
  615.         if (!w->mailbox.flag_up)
  616.             force_redraw = w->mailbox.flag_up = TRUE;
  617.     } 
  618.     w->mailbox.last_size = mailboxsize;
  619.     if (force_redraw) redraw_mailbox (w);
  620.     return;
  621. }
  622.  
  623. /*
  624.  * get user name for building mailbox
  625.  */
  626.  
  627. static void GetMailFile (w)
  628.     MailboxWidget w;
  629. {
  630.     char *getlogin();
  631.     char *username;
  632.  
  633.     /* MAIL env var overrides any hard-coded mail dir */
  634.     username = getenv( "MAIL" );
  635.     if (username!=(char *)NULL) {
  636.         w->mailbox.filename = (String) XtMalloc (strlen (username) + 1);
  637.         strcpy (w->mailbox.filename, username);
  638.         return;
  639.     }
  640.  
  641.     username = getlogin();
  642.     if (!username) {
  643.         struct passwd *pw = getpwuid (getuid ());
  644.  
  645.         if (!pw) {
  646.             fprintf (stderr, "%s:  unable to find a username for you.\n",
  647.                  "Mailbox widget");
  648.             CloseDown (w, 1);
  649.         }
  650.         username = pw->pw_name;
  651.     }
  652.     w->mailbox.filename = (String) XtMalloc (strlen (MAILBOX_DIRECTORY) + 1 +
  653.                                              strlen (username) + 1);
  654.     strcpy (w->mailbox.filename, MAILBOX_DIRECTORY);
  655.     strcat (w->mailbox.filename, "/");
  656.     strcat (w->mailbox.filename, username);
  657.     return;
  658. }
  659.  
  660. static void CloseDown (w, status)
  661.     MailboxWidget w;
  662.     int status;
  663. {
  664.     Display *dpy = XtDisplay (w);
  665.  
  666.     XtDestroyWidget ((Widget)w);
  667.     XCloseDisplay (dpy);
  668.     exit (status);
  669. }
  670.  
  671. /*
  672.  * Called by Initialize() to read XPM icon files
  673.  * and create XPM image data from their contents
  674.  */
  675. static void ReadIconFile (w, flag)
  676.     MailboxWidget w;
  677.     Bool flag;
  678. {
  679.     String            name;
  680.     char            aname[255], *ch=NULL;
  681.     int                code;
  682.     struct _mbimage    *im;
  683.     XpmImage        *imp;
  684.     int                i;
  685.  
  686.     if ( flag ) {
  687.         if (w->mailbox.mail_numofxpmfile > 1) {
  688.             /* append a number before a file name */
  689.             ch = strrchr(w->mailbox.mail_xpmfile, '/');
  690.             if (ch) *ch = '\0';
  691.         }
  692.         for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {
  693.             if (w->mailbox.mail_numofxpmfile > 1)
  694.                 sprintf(aname, "%s/%d%s", w->mailbox.mail_xpmfile, i, ch+1);
  695.             else
  696.                 strcpy(aname, w->mailbox.mail_xpmfile);    /* 1: file for "mail" */
  697.             im = &w->mailbox.full[i];
  698.             imp = &mail_xpmimg[i];
  699.             code = XpmReadFileToXpmImage( aname, imp, (XpmInfo *)NULL );
  700.             if ( code == XpmSuccess ) {
  701.                 im->xpmimg = imp;
  702.                 im->width = imp->width;
  703.                 im->height = imp->height;
  704.             }
  705.             else
  706.             {
  707.                 fprintf (stderr, "%s: ReadIconFile(%s): %s\n",
  708.                          "Mailbox widget", aname, XpmGetErrorString(code));
  709.                 w->mailbox.mail_numofxpmfile = i;
  710.                 if (w->mailbox.mail_numofxpmfile == 0)
  711.                     w->mailbox.mail_numofxpmfile = 1;
  712.                 break;
  713.             }
  714.         }
  715.     }
  716.     else {
  717.         name = w->mailbox.nomail_xpmfile; /* False: file for no "mail" */
  718.         im = &w->mailbox.empty;
  719.         imp = &nomail_xpmimg;
  720.         code = XpmReadFileToXpmImage( name, imp, (XpmInfo *)NULL );
  721.         if ( code == XpmSuccess ) {
  722.             im->xpmimg = imp;
  723.             im->width = imp->width;
  724.             im->height = imp->height;
  725.         }
  726.         else
  727.             fprintf (stderr, "%s: ReadIconFile(%s): %s\n",
  728.                  "Mailbox widget", name, XpmGetErrorString(code));
  729.     }
  730. }
  731.  
  732. /*
  733.  * Called by Initialize() to create XPM image
  734.  * data from the default (hard-coded) XPM icons
  735.  */
  736. static void DefaultXpmImage(w, flag)
  737.     MailboxWidget w;
  738.     Bool flag;
  739. {
  740. #define MakeXpmImage()    { \
  741.         code = XpmCreateXpmImageFromData (datap, imp, (XpmInfo *)NULL); \
  742.         if ( code == XpmSuccess ) { \
  743.             im->xpmimg = imp; \
  744.             im->width = imp->width; \
  745.             im->height = imp->height; \
  746.         } \
  747.         else { \
  748.             fprintf (stderr, "%s: DefaultXpmImage(): %s\n", \
  749.                      "Mailbox widget", XpmGetErrorString(code)); \
  750.             CloseDown (w, 1); \
  751.         } \
  752.     }
  753.  
  754.     char            **datap;
  755.     int                code;
  756.     struct _mbimage    *im;
  757.     XpmImage        *imp;
  758.     int                i;
  759.  
  760.     if ( flag ) {
  761.         for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {
  762.             datap = (i % 2)? xnomail_xpm: xmail_xpm; /* 1: data for "mail" */
  763.             im = &w->mailbox.full[i];
  764.             imp = &mail_xpmimg[i];
  765.             MakeXpmImage();
  766.         }
  767.     }
  768.     else {
  769.         datap = xnomail_xpm; /* False: data for "no mail" */
  770.         im = &w->mailbox.empty;
  771.         imp = &nomail_xpmimg;
  772.         MakeXpmImage();
  773.     }
  774. #undef MakeXpmImage
  775. }
  776.  
  777. /* ARGSUSED */
  778. static Boolean SetValues (gcurrent, grequest, gnew)
  779.     Widget gcurrent, grequest, gnew;
  780. {
  781.     MailboxWidget current = (MailboxWidget) gcurrent;
  782.     MailboxWidget new = (MailboxWidget) gnew;
  783.     Boolean redisplay = FALSE;
  784.  
  785.     if (current->mailbox.update != new->mailbox.update) {
  786.         if (current->mailbox.interval_id) 
  787.         XtRemoveTimeOut (current->mailbox.interval_id);
  788.         new->mailbox.interval_id =
  789.             XtAppAddTimeOut (XtWidgetToApplicationContext(gnew),
  790.                              new->mailbox.update * 1000, clock_tic,
  791.                              (XtPointer) gnew);
  792.     }
  793.  
  794.     return (redisplay);
  795. }
  796.  
  797.  
  798. /*
  799.  * drawing code
  800.  */
  801.  
  802. static void redraw_mailbox (w)
  803.     MailboxWidget w;
  804. {
  805.     static                int ctrig=0;
  806.     register Display    *dpy = XtDisplay (w);
  807.     register Window        win = XtWindow (w);
  808.     GC                    gc = w->mailbox.gc;
  809.     struct _mbimage        *im;
  810.     Widget                parent;
  811.  
  812.     if (w->mailbox.flag_up) {        /* draw the "mail" icon */
  813.         if (w->mailbox.mail_numofxpmfile > 1) {
  814.             if (w->mailbox.first_trig) {
  815.                 w->mailbox.anim_int_id = XtAppAddTimeOut (
  816.                             XtWidgetToApplicationContext((Widget) w),
  817.                             w->mailbox.mail_animupdate, clock_tic_anim, 
  818.                             (XtPointer) w);
  819.                 w->mailbox.anim_id = 0;
  820.                 w->mailbox.first_trig = 0;
  821.                 ctrig = 0;
  822.             } else {
  823.                 /* This route called twice (The second one from ReDisplay()) */
  824.                 if ((++ctrig % 2) == 0) {
  825.                     w->mailbox.anim_id = (w->mailbox.anim_id + 1) 
  826.                                             % (w->mailbox.mail_numofxpmfile);
  827.                     if (w->mailbox.mail_animonce && (w->mailbox.anim_id == 0)) {
  828.                         if (w->mailbox.anim_int_id != -1) {
  829.                             XtRemoveTimeOut(w->mailbox.anim_int_id);
  830.                             w->mailbox.anim_int_id = -1;
  831.                         }
  832.                         w->mailbox.anim_id = w->mailbox.mail_numofxpmfile - 1;
  833.                     }
  834.                     ctrig = 0;
  835.                 }
  836.     
  837.                 if (w->mailbox.anim_int_id == -1)
  838.                     return;
  839.             }
  840.             im = &(w->mailbox.full[w->mailbox.anim_id]);
  841.         }
  842.         else im = &(w->mailbox.full[0]);
  843.     } else {                        /* draw the "no mail" icon */
  844.         im = &w->mailbox.empty;
  845.         w->mailbox.first_trig = 1;
  846.         if (w->mailbox.anim_int_id != -1) {
  847.             XtRemoveTimeOut(w->mailbox.anim_int_id);
  848.             w->mailbox.anim_int_id = -1;
  849.         }
  850.     }
  851.     XClearWindow (dpy, win);
  852.     XCopyArea (dpy, im->pixmap, win, gc, 0, 0, im->width, im->height, 0, 0);
  853.  
  854.     /*
  855.      * XXX - temporary hack; walk up widget tree to find top most parent (which
  856.      * will be a shell) and mash it to have our shape.  This will be replaced
  857.      * by a special shell widget.
  858.      */
  859.  
  860.     for (parent = (Widget) w; XtParent(parent);
  861.         parent = XtParent(parent));
  862.  
  863.     if (im->bitmap != w->mailbox.shape_cache.mask) {
  864.         XShapeCombineMask (XtDisplay(parent), XtWindow(parent),
  865.                            ShapeBounding, 0, 0, im->bitmap, ShapeSet);
  866.         w->mailbox.shape_cache.mask = im->bitmap;
  867.     }
  868.  
  869.     return;
  870. }
  871.  
  872. #ifdef COM_AUDIO
  873. static int comm_play (command, soundfile)
  874.     char *command;
  875.     char *soundfile;
  876. {
  877.     char comm[255]; /* we suppose the command will be smaller than 255 chars */
  878.     int  result;
  879.  
  880.     if ( ( command == NULL ) || ( soundfile == NULL ) )
  881.         return -1;
  882.  
  883.     sprintf(comm, command, soundfile);
  884.  
  885.     return system(comm);
  886. }
  887. #endif /* COM_AUDIO */
  888.  
  889. #ifndef NO_AUDIO
  890. #define CLOSE_FD(afd)    { if (afd > -1) close(afd); afd = -1; }
  891.  
  892. #if defined(linux) || defined(__FreeBSD__)
  893. #define INIT_FD    { audiofd = filefd = mixer_fd = -1; }
  894. #define END_FD    { CLOSE_FD(audiofd); CLOSE_FD(filefd); CLOSE_FD(mixer_fd); return; }
  895. #else
  896. #define INIT_FD    { audiofd = filefd = 0; }
  897. #define END_FD    { CLOSE_FD(audiofd); CLOSE_FD(filefd); return; }
  898. #endif /* if defined(linux) */
  899. #endif /* ifndef NO_AUDIO  */
  900.  
  901. static void beep (w)
  902.     MailboxWidget w;
  903. {
  904. #ifndef NO_AUDIO
  905. #ifdef COM_AUDIO
  906.     if (comm_play(w->mailbox.mail_sndcomm, w->mailbox.mail_sndfile))
  907. #else
  908. #ifdef NCD_AUDIO
  909.     char    *auservername = NULL;
  910. #elif defined(RPLAY_AUDIO)
  911.     char    *rplay_name;
  912. #endif /* ifdef NCD_AUDIO */
  913.     int        audiofd, filefd;
  914.     int        rn, wn, len;
  915.     unsigned char    buf[256];
  916. #ifdef SUN_AUDIO
  917.     Audio_filehdr    *au_hdr;
  918. #if defined(linux) || defined(__FreeBSD__)
  919.     StereoVolume origVol, volume;
  920.     int                mixer_fd;
  921. #else
  922.     audio_info_t     ais;
  923.     int                origVol;    
  924. #endif /* if defined(linux) */
  925. #endif /* ifdef SUN_AUDIO */
  926.  
  927.     if (w->mailbox.mail_sndfile) {
  928. #ifdef NCD_AUDIO
  929.         aud = AuOpenServer(auservername, 0, NULL, 0, NULL, NULL);
  930.         if (aud) {
  931.             if (!AuSoundPlaySynchronousFromFile(aud, w->mailbox.mail_sndfile, 
  932.                                                 w->mailbox.volume))
  933.                 fprintf(stderr, "%s: Couldn't play file \"%s\"\n", 
  934.                         "Mailbox widget", w->mailbox.mail_sndfile);
  935.  
  936.             AuCloseServer(aud);
  937.             return;
  938.         }
  939. #elif defined(RPLAY_AUDIO)
  940.         rplay_name = rplay_default_host();
  941.         if (rplay_host_volume(rplay_name, w->mailbox.mail_sndfile,
  942.                               (int)(w->mailbox.volume*2.55)) < 0)
  943.             fprintf(stderr, "%s: Rplay couldn't play file \"%s\"\n", 
  944.                     "Mailbox widget", w->mailbox.mail_sndfile);
  945.         else
  946.             return;
  947. #endif /* ifdef NCD_AUDIO */
  948. #ifdef SUN_AUDIO
  949.         INIT_FD;
  950.         audiofd = open( "/dev/audio", O_WRONLY | O_NDELAY ); 
  951.         if (audiofd < 0) {
  952.             fprintf(stderr, "%s: Problem opening /dev/audio.\n",
  953.                     "Mailbox widget");
  954.             END_FD;
  955.         }
  956. #if defined(linux) || defined(__FreeBSD__)
  957.         if ( (mixer_fd=open(DEV_MIXER, O_RDWR, 0)) < 0 ) {
  958.             fprintf(stderr, "Can't open %s: ", DEV_MIXER);
  959.             END_FD;
  960.         }
  961.  
  962.         if ( ioctl(mixer_fd, SOUND_MIXER_READ_PCM, &origVol) < 0 ) {
  963.             perror("Can't obtain current volume settings");
  964.             END_FD;
  965.         }
  966.  
  967.         setvolume(LEFT|RIGHT, (unsigned char)w->mailbox.volume, &volume);
  968.  
  969.         if ( ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, &volume) < 0 ) {
  970.             fprintf(stderr, "Can't set current volume settings");
  971.             END_FD;
  972.         }
  973.  
  974.         /* The following is required for the setting to take into effect
  975.         CLOSE_FD(mixer_fd); */
  976. #else
  977.         if( ioctl( audiofd, AUDIO_GETINFO, &ais ) ) {
  978.             fprintf(stderr, "%s: Problem retrieving /dev/audio info.\n",
  979.                     "Mailbox widget");
  980.             END_FD;
  981.         }
  982.         origVol = ais.play.gain;
  983.         ais.play.gain = w->mailbox.volume;
  984.         if( ioctl( audiofd, AUDIO_SETINFO, &ais ) ) {
  985.             fprintf(stderr, "%s: Problem setting /dev/audio info.\n",
  986.                     "Mailbox widget");
  987.             END_FD;
  988.         }
  989. #endif /* if defined(linux) */
  990.         filefd = open(w->mailbox.mail_sndfile, O_RDONLY);
  991.         if (filefd < 0) {
  992.             fprintf(stderr, "%s: Couldn't play file \"%s\"\n", 
  993.                 "Mailbox widget", w->mailbox.mail_sndfile);
  994.             END_FD;
  995.         }
  996.  
  997.         /* Read in the audio header */
  998.         rn = read(filefd, buf, sizeof(Audio_filehdr)); 
  999.  
  1000.         if (rn > 0 && strncmp(buf, ".snd", 4) != 0) {
  1001.             fprintf(stderr, "%s: Invalid audio file format.\n",
  1002.                     "Mailbox widget");
  1003.             END_FD;
  1004.         }
  1005.  
  1006.         /* Strip the header */
  1007.         au_hdr = (Audio_filehdr *)buf;
  1008. #if defined(linux) || defined(__FreeBSD__)
  1009.         rn = ntohl(au_hdr->hdr_size) - sizeof(Audio_filehdr);     
  1010. #else
  1011.         rn = au_hdr->hdr_size - sizeof(Audio_filehdr);
  1012. #endif /* if defined(linux) */
  1013.         for( ; rn > 0; ) {
  1014.             len = min(rn, sizeof(buf));
  1015.             len = read(filefd, buf, len); 
  1016.             rn -= len;    
  1017.         }
  1018.  
  1019.         while(1) {
  1020.             rn = read(filefd, buf, sizeof(buf));
  1021.             if (rn < 0) {
  1022.                 fprintf(stderr, "%s: Error reading from file \"%s\"\n", 
  1023.                     "Mailbox widget", w->mailbox.mail_sndfile);
  1024.                 END_FD;
  1025.             }
  1026.             if (rn == 0)
  1027.                 break;
  1028.             while(1) {
  1029.                 wn = write(audiofd, buf, rn);
  1030.                 if ( wn < 0 ) {
  1031.                     fprintf(stderr, "%s: Error writing to /dev/audio.\n", 
  1032.                         "Mailbox widget");
  1033.                     END_FD;
  1034.                 }
  1035.                 if ( wn != 0 )
  1036.                     break;
  1037.                 usleep(1000);
  1038.             }
  1039.         }
  1040. #if defined(linux) || defined(__FreeBSD__)
  1041.         CLOSE_FD(audiofd);
  1042.  
  1043.         if ( ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, &origVol) < 0 ) {
  1044.             fprintf(stderr, "Can't reset volume settings");
  1045.         }
  1046. #else
  1047.         ais.play.gain = origVol;
  1048.         if( ioctl( audiofd, AUDIO_SETINFO, &ais ) ) {
  1049.             fprintf(stderr, "%s: Problem setting /dev/audio info.\n",
  1050.                     "Mailbox widget");
  1051.         }
  1052. #endif /* if defined(linux) */
  1053.         END_FD;
  1054. #endif /* #ifdef SUN_AUDIO */
  1055.     }
  1056.     else
  1057. #endif /* #ifdef COM_AUDIO */
  1058. #endif /* #ifndef NO_AUDIO */
  1059.         XBell (XtDisplay (w), w->mailbox.volume);
  1060.     return;
  1061. }
  1062.  
  1063.